#include "Graphics/Matrix.hpp"

namespace Graph
{

Matrix::Matrix()
{
    m_data.fill(0.0);
}

Matrix::Matrix(const double value)
{
    m_data.fill(value);
}

Matrix::Matrix(const Matrix &other): m_data(other.m_data)
{
}

Matrix::Matrix(const std::array<double, ELEMENTS_COUNT> &data): m_data(data)
{
}

Matrix::~Matrix()
{
}

const double * Matrix::operator [](const int32_t i) const
{
    return m_data.data() + i * COLS_COUNT;
}

double * Matrix::operator [](const int32_t i)
{
    return m_data.data() + i * COLS_COUNT;
}

const double * Matrix::data() const
{
    return m_data.data();
}

double * Matrix::data()
{
    return m_data.data();
}

//------------------------- Operators ----------------------------------------

bool Matrix::operator ==(const Matrix &other) const
{
    for (int32_t i = ELEMENTS_COUNT - 1; i >= 0; --i)
        if (m_data[i] != other.m_data[i])
            return false;
    return true;
}

bool Matrix::operator !=(const Matrix &other) const
{
    return !(*this == other);
}

Matrix& Matrix::operator =(const Matrix &other)
{
    m_data = other.m_data;
    return *this;
}

Matrix& Matrix::operator +=(const Matrix &other)
{
    for (int32_t i = ELEMENTS_COUNT - 1; i >= 0; --i)
        m_data[i] += other.m_data[i];
    return *this;
}

Matrix& Matrix::operator -=(const Matrix &other)
{
    for (int32_t i = ELEMENTS_COUNT - 1; i >= 0; --i)
        m_data[i] -= other.m_data[i];
    return *this;
}

Matrix& Matrix::operator *=(const double a)
{
    for (int32_t i = ELEMENTS_COUNT - 1; i >= 0; --i)
        m_data[i] *= a;
    return *this;
}

Matrix& Matrix::operator /=(const double a)
{
    return (*this) *= 1.0/a;
}

Matrix Matrix::operator -() const
{
    Matrix res;
    for (int i = Matrix::ELEMENTS_COUNT - 1; i >= 0; --i)
        res.m_data[i] = -m_data[i];
    return res;
}

//--------------------- Non member operators ---------------------------------

Matrix operator +(const Matrix &m1, const Matrix& m2)
{
    Matrix res = m1;
    return res += m2;
}

Matrix operator -(const Matrix &m1, const Matrix& m2)
{
    Matrix res = m1;
    return res -= m2;
}

Matrix operator *(const Matrix &m1, const Matrix& m2)
{
    Matrix res;
    for (int32_t i = 0; i < Matrix::ROWS_COUNT; ++i)
        for (int32_t k = 0; k < Matrix::ROWS_COUNT; ++k)
            for (int32_t j = 0; j < Matrix::COLS_COUNT; ++j)
                res[i][j] += m1[i][k] * m2[k][j];
    return res;
}

Matrix operator *(const Matrix &m, const double a)
{
    Matrix res = m;
    return res *= a;
}

Matrix operator *(const double a, const Matrix &m)
{
    return m * a;
}

Matrix operator /(const Matrix &m, const double a)
{
    return m * (1.0 / a);
}

}
